package cn.qianxun.meta.common.security.config;

import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.router.SaHttpMethod;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import cn.qianxun.meta.common.core.constant.Constants;
import cn.qianxun.meta.common.core.constant.HttpStatus;
import cn.qianxun.meta.common.satoken.config.SecurityProperties;
import cn.qianxun.meta.common.satoken.utils.StpAppIdUtil;
import cn.qianxun.meta.common.security.interceptor.RepeatSubmitInterceptor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 权限安全配置
 *
 * @author Lion Li
 */
@Slf4j
@AutoConfiguration
@RequiredArgsConstructor
public class SecurityConfiguration implements WebMvcConfigurer {

    private final SecurityProperties securityProperties;


    /**
     * 注册 Sa-Token 拦截器
     *
     * @param registry registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册路由拦截器，自定义验证规则
        registry.addInterceptor(new SaInterceptor(handle -> {
            String requestPath = SaHolder.getRequest().getRequestPath();
            log.info("Sa-Token 拦截器请求路径为：{}", requestPath);
            if (requestPath.startsWith(Constants.OPEN_API)) {
                // 拦截所有的 APP应用用户访问 并且排除不需要拦截的
                SaRouter.match("/**").check(r -> StpAppIdUtil.checkLogin());
            } else if (requestPath.contains("/web/v1/upload/authUploadByBucketName")) {
                /*//自定义上传
                SaRequest request = SaHolder.getRequest();
                String authorization = request.getParam("Authorization");
                if (!StpUtil.isLogin(StpUtil.getLoginId(authorization))) {
                    throw NotLoginException.newInstance(StpUtil.getLoginType(), INVALID_TOKEN, INVALID_TOKEN_MESSAGE, authorization).setCode(SaErrorCode.CODE_11012);
                }*/
            }else {
                //拦截所有的 后台用户访问 并且排除不需要拦截的
                SaRouter.match("/**").notMatch(securityProperties.getExcludes()).check(r -> StpUtil.checkLogin());
            }
        })).addPathPatterns("/**").excludePathPatterns(securityProperties.getExcludes());
        registry.addInterceptor(new RepeatSubmitInterceptor()).addPathPatterns("/**");
    }

    /**
     * 校验是否从网关转发
     */
    @Bean
    public SaServletFilter getSaServletFilter() {
        return new SaServletFilter()
                .addInclude("/**")
                .addExclude(securityProperties.getExcludes())
                .setAuth(obj -> {
                    //if (SaManager.getConfig().getCheckSameToken()) {
                    //  SaSameUtil.checkCurrentRequestToken();
                    //}
                })
                .setError(e -> SaResult.error("认证失败，无法访问系统资源").setCode(HttpStatus.UNAUTHORIZED))
                // 前置函数：在每次认证函数之前执行（BeforeAuth 不受 includeList 与 excludeList 的限制，所有请求都会进入）
                .setBeforeAuth(r -> {
                    // ---------- 设置一些安全响应头 ----------
                    SaHolder.getResponse()
                            // 服务器名称
                            .setServer("meta-server")
                            // 是否可以在iframe显示视图： DENY=不可以 | SAMEORIGIN=同域下可以 | ALLOW-FROM uri=指定域名下可以
                            .setHeader("X-Frame-Options", "SAMEORIGIN")
                            // 是否启用浏览器默认XSS防护： 0=禁用 | 1=启用 | 1; mode=block 启用, 并在检查到XSS攻击时，停止渲染页面
                            .setHeader("X-XSS-Protection", "1; mode=block")
                            // 禁用浏览器内容嗅探
                            .setHeader("X-Content-Type-Options", "nosniff")
                            // 允许指定域访问跨域资源
                            .setHeader("Access-Control-Allow-Origin", "*")
                            // 允许所有请求方式
                            .setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
                            // 有效时间
                            .setHeader("Access-Control-Max-Age", "3600")
                            // 允许的header参数
                            .setHeader("Access-Control-Allow-Headers", "*");
                    // 如果是预检请求，则立即返回到前端
                    SaRouter.match(SaHttpMethod.OPTIONS).back();
                })

                ;
    }

}
